<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title>TaskGo · Settings</title>
    <link rel="manifest" href="/manifest.json">
    <meta name="theme-color" content="#2563eb">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="default">
    <meta name="apple-mobile-web-app-title" content="TaskGo">

    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="/static/css/style.css">
    <script src="/static/js/tailwind_config.js"></script>
    <link rel="stylesheet" href="/static/css/theme.css">
    <script src="/static/js/script.js" defer></script>
</head>
<body class="bg-background dark:bg-background-dark text-gray-800 dark:text-secondary-200 antialiased min-h-[100dvh]">
    <header class="bg-surface dark:bg-surface-dark border-b border-border dark:border-border-dark p-4">
        <div class="flex items-center justify-between w-full max-w-screen-xl mx-auto">
            <div class="flex items-center space-x-2">
                <button id="settings-back-btn" class="p-2 rounded-lg border border-border dark:border-border-dark text-secondary hover:text-primary transition-colors" aria-label="返回主页" title="返回">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
                    </svg>
                </button>
                <h1 class="text-xl font-semibold">Settings</h1>
            </div>
        </div>
    </header>

    <main class="w-full max-w-screen-xl mx-auto p-4">
        <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-6">
            <section class="bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-sm p-6">
                <h2 class="text-sm font-medium text-secondary mb-3">Theme Skin</h2>
                <div class="space-y-2">
                    <label class="flex items-center space-x-2">
                        <input type="radio" id="theme-light" name="theme-mode" value="light" class="w-4 h-4 text-primary focus:ring-primary">
                        <span class="text-sm">Light</span>
                    </label>
                    <label class="flex items-center space-x-2">
                        <input type="radio" id="theme-dark" name="theme-mode" value="dark" class="w-4 h-4 text-primary focus:ring-primary">
                        <span class="text-sm">Dark</span>
                    </label>
                    <label class="flex items-center space-x-2">
                        <input type="radio" id="theme-system" name="theme-mode" value="system" class="w-4 h-4 text-primary focus:ring-primary">
                        <span class="text-sm">System</span>
                    </label>
                </div>
            </section>

            <section class="bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-sm p-6">
                <h2 class="text-sm font-medium text-secondary mb-3">Profile Settings</h2>
                <form id="avatar-form" class="space-y-4">
                    <div class="flex items-center space-x-4">
                        <img id="current-avatar" src="/static/icons/avatar.png" alt="当前头像" class="w-16 h-16 rounded-full border border-border dark:border-border-dark">
                        <div>
                            <input type="file" id="avatar-input" accept="image/*" class="hidden">
                            <button type="button" id="choose-avatar-btn" class="px-4 py-2 text-sm bg-background dark:bg-background-dark border border-border dark:border-border-dark rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800">Select Picture</button>
                        </div>
                    </div>
                    <button type="submit" class="w-full bg-primary text-white py-2 rounded-lg hover:bg-primary/90">Upload avatar</button>
                </form>
            </section>

            <section class="bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-sm p-6">
                <h2 class="text-sm font-medium text-secondary mb-3">Change Password</h2>
                <form id="password-form" class="space-y-4">
                    <input type="password" id="current-password" placeholder="Current Password" required class="w-full px-4 py-2 bg-background dark:bg-background-dark border border-border dark:border-border-dark rounded-lg focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary">
                    <input type="password" id="new-password" placeholder="New Password" required class="w-full px-4 py-2 bg-background dark:bg-background-dark border border-border dark:border-border-dark rounded-lg focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary">
                    <button type="submit" class="w-full bg-primary text-white py-2 rounded-lg hover:bg-primary/90">Update Password</button>
                </form>
            </section>
        </div>

        <section class="bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-sm p-6">
            <h2 class="text-sm font-medium text-secondary mb-3">About</h2>
            <div id="version-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"></div>
        </section>
    </main>

    <script>
    // 主题应用与系统偏好
    let currentTheme = localStorage.getItem('theme-mode') || 'system';
    function applyTheme(theme) {
        localStorage.setItem('theme-mode', theme);
        currentTheme = theme;
        if (theme === 'dark') {
            document.documentElement.classList.add('dark');
        } else if (theme === 'light') {
            document.documentElement.classList.remove('dark');
        } else if (theme === 'system') {
            if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
                document.documentElement.classList.add('dark');
            } else {
                document.documentElement.classList.remove('dark');
            }
        }
    }
    if (window.matchMedia) {
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
            if (currentTheme === 'system') {
                if (e.matches) {
                    document.documentElement.classList.add('dark');
                } else {
                    document.documentElement.classList.remove('dark');
                }
            }
        });
    }

    document.addEventListener('DOMContentLoaded', () => {
        applyTheme(currentTheme);
        const radio = document.querySelector(`input[name="theme-mode"][value="${currentTheme}"]`);
        if (radio) radio.checked = true;
        document.querySelectorAll('input[name="theme-mode"]').forEach(r => {
            r.addEventListener('change', e => { if (e.target.checked) applyTheme(e.target.value); });
        });

        // 返回主页
        document.getElementById('settings-back-btn').addEventListener('click', () => {
            window.location.href = '/';
        });

        // 头像上传
        document.getElementById('choose-avatar-btn').addEventListener('click', () => {
            document.getElementById('avatar-input').click();
        });
        function showDialog(title, message, options) {
            const mask = document.createElement('div');
            mask.className = 'fixed inset-0 bg-black/40 z-50 flex items-center justify-center p-4';
            const panel = document.createElement('div');
            panel.className = 'bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-xl w-full max-w-sm p-6';
            const h = document.createElement('h3'); h.className = 'text-lg font-semibold mb-2'; h.textContent = title || 'Notice';
            const p = document.createElement('p'); p.className = 'text-sm text-secondary'; p.textContent = message || '';
            const actions = document.createElement('div'); actions.className = 'mt-6 flex justify-end space-x-3';
            const okBtn = document.createElement('button'); okBtn.className = 'px-3 py-2 rounded bg-primary text-white hover:bg-primary/90'; okBtn.textContent = (options && options.okText) || 'OK';
            actions.appendChild(okBtn);
            if (options && options.cancelText) {
                const cancelBtn = document.createElement('button'); cancelBtn.className = 'px-3 py-2 rounded border text-secondary hover:bg-background'; cancelBtn.textContent = options.cancelText;
                actions.insertBefore(cancelBtn, okBtn);
                cancelBtn.addEventListener('click', () => { if (mask.parentNode) mask.remove(); if (options && typeof options.onCancel === 'function') options.onCancel(); });
            }
            panel.appendChild(h); panel.appendChild(p); panel.appendChild(actions);
            mask.appendChild(panel); document.body.appendChild(mask);
            okBtn.addEventListener('click', () => { if (mask.parentNode) mask.remove(); if (options && typeof options.onOk === 'function') options.onOk(); });
        }

        document.getElementById('avatar-form').addEventListener('submit', async (e) => {
            e.preventDefault();
            const file = document.getElementById('avatar-input').files[0];
            if (!file) { showDialog('Upload Avatar', 'Please select a picture'); return; }
            if (file.size > 1 * 1024 * 1024) { showDialog('Upload Avatar', 'Image size must be less than 1MB'); return; }
            const formData = new FormData();
            const converted = typeof convertImageToWebp === 'function' ? await convertImageToWebp(file) : file;
            formData.append('avatar', converted);
            const token = localStorage.getItem('token');
            const res = await fetch('/api/user/avatar', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: formData });
            if (res.ok) { const { data } = await res.json(); document.getElementById('current-avatar').src = data.avatar_url; showDialog('Upload Avatar', 'Avatar updated successfully'); }
            else { const { error } = await res.json(); showDialog('Upload Avatar', `Error: ${error}`); }
        });

        // 密码更新
        document.getElementById('password-form').addEventListener('submit', async (e) => {
            e.preventDefault();
            const currentPassword = document.getElementById('current-password').value;
            const newPassword = document.getElementById('new-password').value;
            const token = localStorage.getItem('token');
            const res = await fetch('/api/user/password', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ current_password: currentPassword, new_password: newPassword }) });
            if (res.ok) { showDialog('Update Password', 'Password updated successfully'); document.getElementById('password-form').reset(); }
            else { const { error } = await res.json(); showDialog('Update Password', `Error: ${error}`); }
        });

        // 版本信息读取与渲染（从 config.json 获取）
        // 中文注释：在页面底部展示软件版本信息，桌面端每行显示多个，移动端每行显示一个
        fetch('/static/config.json')
            .then(res => res.ok ? res.json() : Promise.reject('配置文件加载失败'))
            .then(cfg => {
                const items = [
                    { label: 'Version', value: cfg.version },
                    { label: 'Build Date', value: cfg.build_date },
                    { label: 'Commit', value: (cfg.commit || '').slice(0, 7) },
                    { label: 'App Name', value: cfg.name },
                ].filter(i => i.value);
                const grid = document.getElementById('version-grid');
                grid.innerHTML = items.map(i => `
                    <div class="border border-border dark:border-border-dark rounded-xl p-4 bg-background dark:bg-background-dark">
                        <div class="text-xs text-secondary mb-1">${i.label}</div>
                        <div class="text-sm font-medium">${i.value}</div>
                    </div>
                `).join('');
            })
            .catch(err => {
                const grid = document.getElementById('version-grid');
                grid.innerHTML = `<div class="text-sm text-danger">Failed to load version: ${err}</div>`;
            });
        // Token 管理
        const tokenContainer = document.createElement('section');
        tokenContainer.className = 'bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-sm p-6 mt-6';
        tokenContainer.innerHTML = `
            <h2 class="text-sm font-medium text-secondary mb-3">API Tokens</h2>
            <div class="flex flex-col sm:flex-row sm:items-center gap-2 mb-4 w-full">
                <input id="token-name" class="px-3 py-2 bg-background dark:bg-background-dark border border-border rounded-lg w-full sm:w-auto sm:flex-1" placeholder="Token name (optional)">
                <select id="token-duration" class="px-3 py-2 bg-background dark:bg-background-dark border border-border rounded-lg w-full sm:w-44">
                    <option value="1m">1 Month</option>
                    <option value="1d">1 Day</option>
                    <option value="1y">1 Year</option>
                    <option value="permanent">Permanent</option>
                </select>
                <button id="create-token-btn" class="px-3 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 w-full sm:w-auto">Generate Token</button>
            </div>
            <div id="tokens-list" class="space-y-2"></div>
        `;
        document.querySelector('main').appendChild(tokenContainer);

        async function loadTokens() {
            const token = localStorage.getItem('token');
            const res = await fetch('/api/tokens', { headers: { 'Authorization': `Bearer ${token}` } });
            const wrap = document.getElementById('tokens-list');
            wrap.innerHTML = '';
            if (!res.ok) return;
            const { data } = await res.json();
            data.forEach(t => {
                const row = document.createElement('div');
                row.className = 'p-3 border border-border rounded-lg bg-background dark:bg-background-dark flex flex-col sm:flex-row sm:items-center justify-between gap-2';
                const left = document.createElement('div');
                left.className = 'text-xs break-all w-full';
                const name = (t.Name || '').trim();
                const exp = new Date(t.ExpiresAt).toLocaleString();
                const preview = t.Token ? (t.Token.slice(0, 8) + '…' + t.Token.slice(-4)) : '';
                left.innerHTML = `<div class="font-medium">${name || 'Unnamed token'}</div><div class="text-secondary">Expires: ${exp}</div><div class="mt-1">${preview}</div>`;
                const right = document.createElement('div');
                right.className = 'flex flex-wrap items-center gap-2 sm:justify-end';
                const copyBtn = document.createElement('button'); copyBtn.className = 'px-2 py-1 bg-primary text-white rounded text-xs'; copyBtn.textContent = 'Copy';
                copyBtn.addEventListener('click', () => { navigator.clipboard.writeText(t.Token); });
                const revokeBtn = document.createElement('button'); revokeBtn.className = 'px-2 py-1 bg-red-500 text-white rounded text-xs'; revokeBtn.textContent = 'Revoke';
                revokeBtn.addEventListener('click', async () => {
                    const token0 = localStorage.getItem('token');
                    await fetch(`/api/tokens/${t.ID}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token0}` } });
                    loadTokens();
                });
                const deleteBtn = document.createElement('button'); deleteBtn.className = 'px-2 py-1 bg-gray-700 text-white rounded text-xs'; deleteBtn.textContent = 'Delete';
                deleteBtn.addEventListener('click', async () => {
                    const token0 = localStorage.getItem('token');
                    await fetch(`/api/tokens/${t.ID}/hard`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token0}` } });
                    loadTokens();
                });
                const updateBtn = document.createElement('button'); updateBtn.className = 'px-2 py-1 bg-blue-500 text-white rounded text-xs'; updateBtn.textContent = 'Update';
                updateBtn.addEventListener('click', async () => {
                    const mask = document.createElement('div'); mask.className = 'fixed inset-0 bg-black/40 z-50 flex items-center justify-center p-4';
                    const panel = document.createElement('div'); panel.className = 'bg-surface dark:bg-surface-dark border border-border dark:border-border-dark rounded-xl shadow-xl w-full max-w-xs p-4';
                    panel.innerHTML = `
                        <h3 class="text-sm font-medium mb-3">Select duration</h3>
                        <input id="upd-name" class="w-full px-3 py-2 bg-background dark:bg-background-dark border border-border rounded-lg mb-3" placeholder="Token name" value="${name}">
                        <select id="upd-duration" class="w-full px-3 py-2 bg-background dark:bg-background-dark border border-border rounded-lg mb-4">
                            <option value="1d">1 Day</option>
                            <option value="1m" selected>1 Month</option>
                            <option value="1y">1 Year</option>
                            <option value="permanent">Permanent</option>
                        </select>
                        <div class="flex justify-end space-x-2">
                            <button id="upd-cancel" class="px-3 py-1 rounded border text-secondary hover:bg-background">Cancel</button>
                            <button id="upd-ok" class="px-3 py-1 rounded bg-primary text-white hover:bg-primary/90">Update</button>
                        </div>
                    `;
                    mask.appendChild(panel); document.body.appendChild(mask);
                    const close = () => { if (mask.parentNode) mask.remove(); };
                    panel.querySelector('#upd-cancel').addEventListener('click', close);
                    panel.querySelector('#upd-ok').addEventListener('click', async () => {
                        const duration = panel.querySelector('#upd-duration').value;
                        const name2 = panel.querySelector('#upd-name').value;
                        const token0 = localStorage.getItem('token');
                        await fetch(`/api/tokens/${t.ID}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token0}` }, body: JSON.stringify({ duration, name: name2 }) });
                        close();
                        loadTokens();
                    });
                });
                right.appendChild(copyBtn);
                right.appendChild(updateBtn);
                right.appendChild(revokeBtn);
                right.appendChild(deleteBtn);
                row.appendChild(left); row.appendChild(right);
                wrap.appendChild(row);
            });
        }

        document.getElementById('create-token-btn').addEventListener('click', async () => {
            const token = localStorage.getItem('token');
            const duration = document.getElementById('token-duration').value;
            const name = document.getElementById('token-name').value;
            const res = await fetch('/api/tokens', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ duration, name }) });
            if (res.ok) loadTokens();
        });

        loadTokens();
    });
    </script>
</body>
</html>